home *** CD-ROM | disk | FTP | other *** search
/ Shareware Grab Bag / Shareware Grab Bag.iso / 090 / byt86jun.arc / INDEXBPP.LST < prev    next >
Encoding:
File List  |  1986-02-07  |  10.3 KB  |  404 lines

  1. const
  2.   IndexMax          = 1000;
  3.   RecCountErr       =   -2;
  4.   NewFileCreated    =   -1;
  5.   NoError           =    0;
  6.   RecordNotFound    =    1;
  7.   NoMoreRoom        =    2;
  8.   AlreadyExists     =    3;
  9.   OutOfRange        =    4;
  10.  
  11. type
  12.  
  13.   Keytype      = string[40];
  14.   FileStr      = string[80];
  15.  
  16.   DataRec = record
  17.     case Boolean of
  18.       True     : (NumRecs     : Integer);
  19.       False    : (Key         : Keytype;
  20.                   theRest     : Whatever;
  21.       { this represents the rest of your data fields } );
  22.   end;
  23.  
  24.   IndexRec = record
  25.     Key        : Keytype;
  26.     Num        : Integer
  27.   end;
  28.  
  29.   IndexList    = array[1..IndexMax] of IndexRec;
  30.  
  31. var
  32.   KList        : IndexList;
  33.   DFile        : file of DataRec;
  34.   MaxRec       : Integer;
  35.  
  36. LISTING 1.  Global definitions and declarations.
  37.  
  38.  
  39. {            compiler-specific file I/O routines                  }
  40. {      these procedures are specific to TURBO Pascal.  If you
  41.        are using another Pascal compiler, you will need to
  42.        modify them appropriately.  Note that TURBO Pascal does
  43.        not support the standard routines GET and PUT, but instead
  44.        uses READ and WRITE.                                       }
  45.  
  46. {$I-} { turn off I/O error checking }
  47.  
  48. procedure FRead(RNum : Integer; var Rec : DataRec; var Error : Integer);
  49. {
  50.      reads record #RNum into Rec
  51. }
  52. begin
  53.   if (RNum < 0) or (RNum > MaxRec)
  54.     then Error := OutOfRange
  55.   else begin
  56.     Seek(DFile,RNum);
  57.     Error := IOResult;
  58.     if Error = NoError then begin
  59.       Read(DFile,Rec);
  60.       Error := IOResult
  61.     end;
  62.     if Error > 0
  63.       then Error := 100 + Error
  64.   end
  65. end; { of proc FRead }
  66.  
  67. procedure FWrite(RNum : Integer; Rec : DataRec; var Error : Integer);
  68. {
  69.      writes record #RNum into Rec
  70. }
  71. begin
  72.   if (RNum < 0) or (RNum > MaxRec)
  73.     then Error := OutOfRange
  74.   else begin
  75.     Seek(DFile,RNum);
  76.     Error := IOResult;
  77.     if Error = NoError then begin
  78.       Write(DFile,Rec);
  79.       Error := IOResult
  80.     end;
  81.     if Error > 0
  82.       then Error := 100 + Error
  83.   end
  84. end; { of proc FRead }
  85.  
  86. procedure FOpen(FileName : FileStr; var Error : Integer);
  87. {
  88.        tries to open FileName; if it doesn't exist, creates
  89.        it with the appropriate header record
  90. }
  91. const
  92.   TurboNoFile  =  1; { "no file" error code for TURBO Pascal }
  93. var
  94.   IOCode       : Integer;
  95.   TRec         : DataRec;
  96. begin
  97.   Assign(DFile,FileName);
  98.   Reset(DFile);
  99.   IOCode := IOResult;
  100.   if IOCode = TurboNoFile then begin { file doesn't exist }
  101.     FillChar(TRec,SizeOf(TRec),0);
  102.     Rewrite(DFile);
  103.     TRec.NumRecs := 0;
  104.     FWrite(0,TRec,Error);
  105.     Close(DFile);
  106.     Assign(DFile,Filename);
  107.     Reset(DFile);
  108.     IOCode := IOResult;
  109.     if IOCode = NoError
  110.       then Error := NewFileCreated
  111.   end;
  112.   if IOCode <> NoError
  113.     then Error := 100 + IOCode;
  114. end; { of proc FOpen }
  115.  
  116. procedure FClose(var Error : Integer);
  117. {
  118.        closes file
  119. }
  120. begin
  121.   Close(DFile);
  122.   Error := IOResult;
  123.   if Error > 0
  124.     then Error := Error + 100
  125. end; { of proc FClose }
  126.  
  127. {$I+} { turn on I/O error checking }
  128.  
  129. LISTING 2a.  File I/O routines specific to TURBO Pascal.
  130. -----------
  131.  
  132.  
  133. {            compiler-specific file I/O routines                  }
  134. {      these procedures are specific to UCSD Pascal.  If you
  135.        are using another Pascal compiler, you will need to
  136.        modify them appropriately.                                 }
  137.  
  138. {$I-} { turn off I/O error checking }
  139.  
  140. procedure FRead(RNum : Integer; var Rec : DataRec; var Error : Integer);
  141. {
  142.      reads record #RNum into Rec
  143. }
  144. begin
  145.   if (RNum < 0) or (RNum > MaxRec)
  146.     then Error := OutOfRange
  147.   else begin
  148.     Seek(DFile,RNum);
  149.     Error := IOResult;
  150.     if Error = NoError then begin
  151.       Get(DFile);
  152.       Error := IOResult;
  153.       if Error = NoError
  154.         then Rec := DFile^
  155.     end;
  156.     if Error <> NoError
  157.       then Error := 100 + Error
  158.   end
  159. end; { of proc FRead }
  160.  
  161. procedure FWrite(RNum : Integer; Rec : DataRec; var Error : Integer);
  162. {
  163.      writes record #RNum into Rec
  164. }
  165. begin
  166.   if (RNum < 0) or (RNum > MaxRec)
  167.     then Error := OutOfRange
  168.   else begin
  169.     Seek(DFile,RNum);
  170.     Error := IOResult;
  171.     if Error = NoError then begin
  172.       DFile^ := Rec;
  173.       Put(DFile);
  174.       Error := IOResult
  175.     end;
  176.     if Error > 0
  177.       then Error := 100 + Error
  178.   end
  179. end; { of proc FRead }
  180.  
  181. procedure FOpen(FileName : FileStr; var Error : Integer);
  182. {
  183.        tries to open FileName; if it doesn't exist, creates
  184.        it with the appropriate header record
  185. }
  186. const
  187.   UCSDNoFile   =  1; { "no file" error code for UCSD Pascal }
  188. var
  189.   IOCode       : Integer;
  190.   TRec         : DataRec;
  191. begin
  192.   Reset(DFile,FileName);
  193.   IOCode := IOResult;
  194.   if IOCode = UCSDNoFile then begin { file doesn't exist }
  195.     FillChar(TRec,SizeOf(TRec),Chr(0));
  196.     Rewrite(DFile,FileName);
  197.     TRec.NumRecs := 0;
  198.     FWrite(0,TRec,Error);
  199.     Close(DFile,Lock);
  200.     Reset(DFile,FileName);
  201.     IOCode := IOResult;
  202.     if IOCode = NoError
  203.       then Error := NewFileCreated
  204.   end;
  205.   if IOCode <> NoError
  206.     then Error := 100 + IOCode;
  207. end; { of proc FOpen }
  208.  
  209. procedure FClose(var Error : Integer);
  210. {
  211.        closes file
  212. }
  213. begin
  214.   Close(DFile,Lock);
  215.   Error := IOResult;
  216.   if Error > 0
  217.     then Error := Error + 100
  218. end; { of proc FClose }
  219.  
  220. {$I+} { turn on I/O error checking }
  221.  
  222. LISTING 2b.  File I/O routines specific to UCSD Pascal.
  223. -----------
  224.  
  225. procedure SortIndexList;
  226. {
  227.      sorts the array KList using a selection sort technique
  228. }
  229. var
  230.   I,J,Min      : Integer;
  231.   Temp         : IndexRec;
  232. begin
  233.   for I := 1 to MaxRec-1 do begin
  234.     Min := I;
  235.     for J := I+1 to MaxRec do
  236.       if KList[J].Key < KList[Min].Key
  237.         then Min := J;
  238.     Temp := KList[I];
  239.     KList[I] := KList[Min];
  240.     KList[Min] := Temp
  241.   end
  242. end; { of proc SortIndexList }
  243.  
  244. procedure InitStuff(FileName : FileStr; var Error : Integer);
  245. {
  246.      sets everything up for indexing system.  This assumes that
  247.      there are no more than IndexMax (=1000) records, and that the
  248.      records are numbered 1..IndexMax.  Record #0 is the header
  249.      record and is used to store the current number of records
  250.      actively being used in the file
  251. }
  252. var
  253.   Indx,TErr           : Integer;
  254.   TRec                : DataRec;
  255. begin
  256.   Error := NoError;
  257.   FOpen(FileName,Error);
  258.   if Error <= NoError then begin
  259.     MaxRec := 0;
  260.     FRead(0,TRec,TErr);
  261.     Error := TErr;
  262.     MaxRec := TRec.NumRecs;
  263.     for Indx := 1 to MaxRec do begin
  264.       FRead(Indx,TRec,TErr);
  265.       if TErr > 0
  266.         then Error := TErr;
  267.       KList[Indx].Key := TRec.Key;
  268.       KList[Indx].Num := Indx
  269.     end;
  270.     SortIndexList
  271.   end
  272. end; { of proc InitStuff }
  273.  
  274. procedure CleanUpStuff(var Error : Integer);
  275. {
  276.      this just does an orderly shutdown and should be called
  277.      before you leave your program (or open another data file)
  278. }
  279. var
  280.   TRec                : DataRec;
  281. begin
  282.   TRec.NumRecs := MaxRec; { save out # of records }
  283.   FWrite(0,TRec,Error);
  284.   FClose(Error)
  285. end; { of proc CleanUpStuff }
  286.  
  287. LISTING 3.  Initialization and cleanup routines.
  288. ----------
  289.  
  290. function FindKey(Key : Keytype) : Integer;
  291. {
  292.      looks for Key in KList; returns location in KList
  293.      if found; otherwise returns - 1
  294. }
  295. var
  296.   L,R,Mid      : Integer;
  297. begin
  298.   L := 1; R := MaxRec;
  299.   repeat
  300.     Mid := (L+R) div 2;
  301.     if Key < KList[Mid].Key
  302.       then R := Mid-1
  303.       else L := Mid+1
  304.   until (Key = KList[Mid].Key) or (L > R);
  305.   if Key = KList[Mid].Key
  306.     then FindKey := Mid
  307.     else FindKey :=  -1
  308. end; { of proc FindKey }
  309.  
  310. procedure GetRecord(Key : Keytype; var Rec : DataRec;
  311.                     var Error : Integer);
  312. {
  313.      looks through KList for Key; if found, returns in Rec.
  314.      It and the routines that follow assume the procedure Seek
  315.      for random access of the file of records.
  316. }
  317. var
  318.   Item                : Integer;
  319. begin
  320.   Error := NoError;
  321.   Item := FindKey(Key);
  322.   if Item > 0
  323.     then FRead(KList[Item].Num,Rec,Error)
  324.     else Error := RecordNotFound
  325. end; { of proc GetRecord }
  326.  
  327. procedure PutRecord(Rec : DataRec; var Error : Integer);
  328. {
  329.      writes Rec out to the file.  If a record with that
  330.      key already exists, then overwrites that record;
  331.      otherwise, adds the record to the end of the file.
  332.      If there's no more room for records, exits with an
  333.      error code
  334. }
  335. var
  336.   Item         : Integer;
  337. begin
  338.   Error := NoError;
  339.   Item := FindKey(Rec.Key);
  340.   if Item >= 0
  341.     then FWrite(KList[Item].Num,Rec,Error)
  342.   else if MaxRec < IndexMax then begin
  343.     MaxRec := MaxRec + 1;
  344.     FWrite(MaxRec,Rec,Error);
  345.     KList[MaxRec].Key := Rec.Key;
  346.     KList[MaxRec].Num := MaxRec;
  347.     SortIndexList
  348.   end
  349.   else Error := NoMoreRoom
  350. end; { of proc PutRecord }
  351.  
  352. LISTING 4.  Basic record access routines.
  353. ----------
  354.  
  355.  
  356. procedure AddRecord(Rec : DataRec; var Error : Integer);
  357. {
  358.      adds a record to the file.  If a record with the same
  359.      key already exists, then exits with an error code
  360. }
  361. var
  362.   Item         : Integer;
  363. begin
  364.   Error := NoError;
  365.   Item := FindKey(Rec.Key);
  366.   if Item > 0
  367.     then Error := AlreadyExists
  368.     else PutRecord(Rec,Error)
  369. end; { of proc AddRecord }
  370.  
  371. procedure DeleteRecord(Key : Keytype; var Error : Integer);
  372. {
  373.      deletes the record with 'Key' by copying the last record
  374.      in the file to that slot, then modifies KList by shuffling
  375.      all the key entries up
  376. }
  377. var
  378.   Item,Last,Max,MVal     : Integer;
  379.   TRec                   : DataRec;
  380. begin
  381.   Error := NoError;
  382.   Item := FindKey(Key);
  383.   if Item = -1
  384.     then Error := RecordNotFound
  385.   else begin
  386.     Max := 1; MVal := KList[Max].Num;
  387.     for Last := 2 to MaxRec do
  388.       if KList[Last].Num > MVal then begin
  389.         Max := Last; MVal := KList[Last].Num
  390.       end;
  391.     if Max <> Item then begin
  392.       FRead(MVal,TRec,Error);             { get last record in file }
  393.       FWrite(KList[Item].Num,TRec,Error); { write over it }
  394.       KList[Max].Num := KList[Item].Num
  395.     end;
  396.     for Last := Item to MaxRec-1 do     { delete KList[Item] }
  397.       KList[Last] := KList[Last+1];
  398.     MaxRec := MaxRec - 1                { adjust # of records }
  399.   end
  400. end; { of proc DeleteRecord }
  401.  
  402. LISTING 5.  Higher-level record access routines.
  403. ----------
  404.